mybatis中Mapper接口注入动态Sql语句 #{ }和${}的区别

1.通过注解@Select

mapper类

// 此处maper注解最好和配置文件中的 mapper-locations: com.wlw.mapper配合使用
@Repository
@Mapper
public interface RecDescribeMapper {

    /* 不加@param注解会报错
     * @param注解必须加上,否则mybatis就会使用默认注解(param1、param2、按顺序...),
     * 这时可以把@select  中的sql语句的#{bf}要改为#{param0},#{ef}要改为#{param1}。
     * 如果不改就会报错:如图1-1所示
     * 所以建议参数都加@Param注解
    @Select({"select  * from RecDescribe where TimeFlag >= #{bF} and TimeFlag <= #{eF}"})
    public List<RecDescribe> selectByTimeFlag(@Param("bF") String bF, @Param("eF") String eF);
}

图1-1

调用类

/**
 * 查询gp数据类
 * @author Thomas
 */
@Service
public class QueryServiceImpl implements QueryService {

    @Autowired
    RecDescribeMapper recDescribeMapper;

    public List<GPS> queryPeriodData(String moduleName, String bTime, String eTime) {

        String bf = bTime.split(" ")[1].replace("-", "");
        String ef = eTime.split(" ")[1].replace("-", "");
        List<RecDescribe> recs = recDescribeMapper.selectByTimeFlag(bf, ef);
        System.out.println(recs);
    }
}

2通过注解 @SelectProvider

SelectProvider类
多个方法参数时,用Map进行代替,否则会找不到对应的参数并报错


org.apache.ibatis.binding.BindingException: 
Parameter 'arg0' not found. Available parameters are [param5, bTime, param6, eTime, moduleTable, kid, gpsTable, model, param3, param4, param1, param2]
    at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:202) ~[mybatis-3.4.2.jar:3.4.2]
    at org.apache.ibatis.builder.annotation.ProviderSqlSource.extractProviderMethodArguments(ProviderSqlSource.java:111) ~[mybatis-3.4.2.jar:3.4.2]
    at org.apache.ibatis.builder.annotation.ProviderSqlSource.createSqlSource(ProviderSqlSource.java:89) ~[mybatis-3.4.2.jar:3.4.2]
    at org.apache.ibatis.builder.annotation.ProviderSqlSource.getBoundSql(ProviderSqlSource.java:73) ~[mybatis-3.4.2.jar:3.4.2]
其中 param0 ~ param5 (有时会出现 arg0 ~ arrg5) 是mybatis的默认参数,对应本例Mapper类中
public List<GPS> queryGpsDataByPeriod(@Param("gpsTable") String gpsTable,
                                          @Param("moduleTable") String moduleTable,
                                          @Param("kid") String kid,
                                          @Param("model")String model,
                                          @Param("bTime")String bTime,
                                          @Param("eTime")String eTime);
方法的参数(按顺序对应)
其他的bTime、eTime等,是因为我加了@Param注解才产生的,如果不加,就没有这些项。
/**
 * 动态生成sql语句
 * 方式1相比于方式2 可以生成动态表名,但是不会进行预编译过程,可能产生sql注入
 * @author Tomas
 * @date 2017/12/13
 */
public class DynamicSqlProvider {

    /**
     * 方式1
     * @param map
     * @return
     */
    public String findGpsPeriodDataBySql1(Map<String, String> map){ 

        /*map中是参数名称和值得key-value对
        * 如果Mapper中加了@Param 注解就可以用参数名作为map的key
        * 时间是无论Mapper接口的方法中加不加@Param注解,都可以用mybatis默认的参数名称(param0 ~ param5)(arg0 ~ arrg5)获取参数值
        */ 

       // 通过参数名称获取对应值
       // String GpsTable = map.get("gpsTable");
       // String moduleTable = map.get("moduleTable");
       // String kid = map.get("kid");
       // String model = map.get("model");
       // String bTime = map.get("bTime").substring(1);
       // String eTime = map.get("eTime").substring(1);

       // 此处用param
        String GpsTable = map.get("param0");
        String moduleTable = map.get("param1");
        String kid = map.get("param2");
        String model = map.get("param3");
        String bTime = map.get("param4").substring(1);
        String eTime = map.get("param5").substring(1);

        // 打印map 可以发现map中已经含有bTime 、param0 ~param5的参数K-V对
        // {param5= 2015-12-02 15:01:42, bTime= 2015-12-02 15:01:42, param6= 2017-12-14 15:01:42, eTime= 2017-12-14 15:01:42, moduleTable=LTM20161124, kid=f01f35d5-24b1-48ad-9246-9c3b7267184b, gpsTable=GPS20161124, model=4G, param3=f01f35d5-24b1-48ad-9246-9c3b7267184b, param4=4G, param1=GPS20161124, param2=LTM20161124}
        System.out.println(map.toString());
        return "Select g.*,m.KID,m.LAC,m.CI,m.GpsTime,'"+ model +"' Model" +
                " from "+ GpsTable +" g left join " + moduleTable +" m " +
                " on g.GpsTime = m.GpsTime where" +
                " m.KID = '"+ kid +"' and m.GpsTime > '"+ bTime +"' and m.GpsTime < '"+ eTime +"'";
    }

    /**
     * 方式2
     * 通过#{key}直接获取map中对应的参数名称,前提是Mapper中加@Param注解
     * 推荐此方式
     * @param map
     * @return
     */
    public String findGpsPeriodDataBySql(Map<String, String> map){
        
        return new SQL(){
            {
                SELECT("g.*,m.KID,m.LAC,m.CI,m.GpsTime,#{model} Model ");
                FROM("GPS20161124 g ");
                INNER_JOIN("MM20161124 m on g.GpsTime = m.GpsTime ");
                WHERE("m.KID = #{kid} and m.GpsTime > #{bTime} and m.GpsTime < #{eTime}");
            }
        }.toString();
    }
}

Mapper类


    /**
     * 不使用@param注解
     * SelectProvider中对应方法的参数 不能 通过名称直接获,只能按参数排序获取 #{param0}
     * @param GpsTable
     * @param moduleTable
     * @param kid
     * @param model
     * @param bTime
     * @param eTime
     * @return
     */
    @SelectProvider(type = DynamicSqlProvider.class,
    method = "findGpsPeriodDataBySql")
    public List<GPS> queryGpsDataByPeriodO(String GpsTable, String moduleTable, String kid, String model, String bTime, String eTime);

    /**
     * 使用字段名
     * SelectProvider中对应方法的参数 可以 通过名称直接获取(对应方式2中的 #{})
     * @param gpsTable
     * @param moduleTable
     * @param kid
     * @param model
     * @param bTime
     * @param eTime
     * @return
     */
    @SelectProvider(type = DynamicSqlProvider.class,
            method = "findGpsPeriodDataBySql")
    public List<GPS> queryGpsDataByPeriod(@Param("gpsTable") String gpsTable,
                                          @Param("moduleTable") String moduleTable,
                                          @Param("kid") String kid,
                                          @Param("model")String model,
                                          @Param("bTime")String bTime,
                                          @Param("eTime")String eTime);

调用类 和 1 中的调用类相似。

3. #和$的区别

#{}
1.#能防止sql注入,$不能
2.$方式一般用于传入数据库对象,例如传入表名.
3.MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
4.#传入值是引用,而$是其本身:
   id = 1, select #{id} from tablename -> select 1  from tablename(引用)
   id = 1, select ${id} from tablename -> select id from tablename
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271